#ifndef __ISceneNodeLoadable_H__
#define __ISceneNodeLoadable_H__


#include <ISceneNode.h>
#include <ILoadableObject.h>
#include <xml/IXmlNode.h>
#include <io/IFileLoadMethods.h>
#include "LoadableObjectList.h"
#include <ITextSceneNode.h>
#include <ISceneManager.h>
#include <IGUIEnvironment.h>
#include <ICameraSceneNode.h>
#include <log/Log.h>

#include "IEmptyNode.h"

namespace irr{
namespace scene{
/***
 * @class ISceneNodeLoadable
 * Класс узла сцены, который сам загрузится, когда придёт его время.
 */
class ISceneNodeLoadable:public irr::scene::ISceneNode,public virtual irr::ILoadableObject{
private:
	irr::io::path fileName;
	ISceneNode*element;
	irr::scene::ITextSceneNode*text;
	irr::core::aabbox3d<f32> size_box;
	irr::core::vector3df size;
	irr::f32 load_distation;
	irr::f32 max_distation_SQ;
	bool auto_update_size;
	bool must_check;
	bool sync_load;
protected:
	virtual void on_load(){
		element=static_cast<scene::ISceneNode*>(getDevice()->getFileLoadMethods()->load(fileName));
		if (!element)
			return;
		element->setParent(this);

		if (getAutoUpdateSize())
			updateSize();
	}
	virtual void on_unload(){
		removeChild(element);
		element=0;
	}
	void calcMaxDistation(){
		irr::f32 max=size_box.MaxEdge.getDistanceFromSQ(irr::core::vector3df(0,0,0));
		irr::f32 min=size_box.MinEdge.getDistanceFromSQ(irr::core::vector3df(0,0,0));
		max_distation_SQ=(max>min?max:min)+(load_distation*load_distation);
	}
public:

	void setLoadDistation(irr::f32 distation){
		load_distation=distation;
		calcMaxDistation();
	}

	irr::f32 getLoadDistation(){
		return load_distation;
	}

	ISceneNode*getNode(){
		return element;
	}

	void setSyncLoad(bool sl){
		sync_load=sl;
	}

	bool getSyncLoad(){
		return sync_load;
	}

	ISceneNodeLoadable(irr::IrrlichtDevice*device,irr::io::path path,
			ISceneNode* parent, s32 id=-1,
			const core::vector3df& position = core::vector3df(0,0,0),
			const core::vector3df& rotation = core::vector3df(0,0,0),
			const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)):fileName(path),ILoadableObject(device),
			ISceneNode(parent,device->getSceneManager(),id,position,rotation,scale){
		size.set(0,0,0);
		//empty=new IEmptyNode(0,device->getSceneManager());
		//LOG("empty REF=%d",(int)empty->getReferenceCount());
		text=this->getSceneManager()->addTextSceneNode(getDevice()->getGUIEnvironment()->getFont("/home/caffeine/PF/northstar/Debug/data/fonts/console.xml"),L"Привет мир!",irr::video::SColor(100,255,255,255),this);
		irr::addToLoadableSceneNodeList(this);
		setLoadDistation(0);
		auto_update_size=true;
		must_check=false;
		this->setDebugDataVisible(irr::scene::EDS_BBOX);
	}

	void initCheck(){
		must_check=true;
	}

	void setAutoUpdateSize(bool update){
		auto_update_size=update;
	}

	bool getAutoUpdateSize(){
		return auto_update_size;
	}

	~ISceneNodeLoadable(){
		irr::removeFromLoadableSceneNodeList(this);
		unload();
		//empty->drop();
	}

	void checkLoad(){
		//LOG("ChildCount=%d",(int)this->getChildren().size());
		irr::core::stringw res;
		switch (getLoadStatus()){
		case ILoadableObject::UnLoaded:
			res=(L"UnLoaded");
			break;
		case ILoadableObject::Loaded:
			res=(L"Loaded");
			break;
		case ILoadableObject::UnLoading:
			res=(L"UnLoading");
			break;
		case ILoadableObject::Loading:
			res=(L"Loading");
			break;
		default:
			res=(L"ERROR");
			break;
		}
		irr::f32 dis=getSceneManager()->getActiveCamera()->getPosition().getDistanceFromSQ(getPosition());
		res+=L" DISTATION=";

		res+=irr::core::stringw(dis);

		res+=L"MAX=";
		res+=irr::core::stringw(max_distation_SQ);
		if (text)
			text->setText(res.c_str());

		//if (dis<50 && this->isUnloaded())
		//	load();

		if (dis<max_distation_SQ && this->isUnloaded())
			if (sync_load)
				load();
			else
				this->load_unsync();

		if (dis>=max_distation_SQ && this->isLoaded())
			if (sync_load)
				unload();
			else
				this->unload_unsync();

		must_check=false;

	}

	virtual void OnRegisterSceneNode(){
		//if (isUnloaded() && getSceneManager()->getActiveCamera()->getPosition().getDistanceFromSQ(getPosition())<max_distation_SQ)
			//load();
		if (must_check)
			checkLoad();

		SceneManager->registerNodeForRendering(this, scene::ESNRP_SOLID);
		irr::scene::ISceneNode::OnRegisterSceneNode();
	}

	virtual void render(){
		getDevice()->getVideoDriver()->draw3DBox(getBoundingBox(),irr::video::SColor(0xFF0000FF));
		getDevice()->getVideoDriver()->draw3DLine(irr::core::vector3df(0,0,0),irr::core::vector3df(0,10,0));
	}

	virtual const core::aabbox3d<f32>& getBoundingBox() const{
		return size_box;
	}

	void setSize(irr::core::vector3df objectSize,irr::core::vector3df offset){
		size=objectSize;
		size_box=irr::core::aabbox3d<f32>(-size.X+offset.X,-size.Y+offset.Y,-size.Z+offset.Z,size.X+offset.X,size.Y+offset.Y,size.Z+offset.Z);
		calcMaxDistation();
	}

	void setSize(irr::f32 radius,irr::core::vector3df offset){
		radius/=2;
		setSize(irr::core::vector3df(radius,radius,radius),offset);
	}

	irr::core::aabbox3d<f32>getTotalBoundingBox(irr::core::aabbox3d<f32> box,irr::scene::ISceneNode*node){
		irr::core::vector3df max=box.MaxEdge;
		irr::core::vector3df min=box.MinEdge;

		if (node->getBoundingBox().MaxEdge>max)
			max=node->getBoundingBox().MaxEdge;
		if (node->getBoundingBox().MinEdge>max)
			min=node->getBoundingBox().MinEdge;

		ISceneNodeList::Iterator it = Children.begin();
		for (; it != Children.end(); ++it){
			if ((*it)->getBoundingBox().MaxEdge>max)
				max=(*it)->getBoundingBox().MaxEdge;
			if ((*it)->getBoundingBox().MinEdge>max)
				min=(*it)->getBoundingBox().MinEdge;
		}
		return irr::core::aabbox3d<f32>(min,max);
	}

	void updateSize(){
		size_box=getTotalBoundingBox(irr::core::aabbox3d<f32>(0,0,0,0,0,0),element);
		irr::f32 max=size_box.MaxEdge.getDistanceFrom(size_box.getCenter());
		irr::f32 min=size_box.MinEdge.getDistanceFrom(size_box.getCenter());
		irr::f32 temp=max>min?max:min;
		size.set(temp,temp,temp);
		calcMaxDistation();
	}
};

}
}

#endif
